﻿using System;
using System.Collections.Generic;
using Fetches.Fetch.Dto;
using Fetches.Fetch.Fetcher;
using Fetches.Fetch.Scheduler.Component;

namespace Fetches.Fetch.Scheduler
{
    /// <summary>
    ///     任务调度器
    /// </summary>
    public abstract class AbstractScheduler : IDuplicateRemover
    {
        /// <summary>
        /// 额外的状态记录，免得每个Fetcher问一遍结束与否导致多次调用结束通知
        /// </summary>
        private bool _finished;

        /// <summary>
        /// 进度通知回调，进度由Scheduler来统计
        /// </summary>
        public Action FinishNotify;

        /// <summary>
        /// 
        /// </summary>
        /// <param name="config"></param>
        /// <param name="uniqueId"></param>
        public virtual void Initialize(string config, long uniqueId)
        {
        }

        /// <summary>
        /// 不考虑grabSomeWork这种形式,而是fetcher将自己发现的链接由Scheduler排除重复并声明已预定
        /// </summary>
        /// <param name="fetcher"></param>
        /// <param name="requests"></param>
        /// <returns></returns>
        public IList<Request> AskForRequestsAssignment(AbstractFetcher fetcher, IList<Request> requests)
        {
            var availableRequests = new List<Request>();
            foreach (var request in requests)
            {
                if (!IsDuplicate(request))
                {
                    availableRequests.Add(request);
                }
            }
            return availableRequests;
        }

        public void Push(Request request)
        {
            if (!IsDuplicate(request))
            {
                PushWhenNoDuplicate(request);
            }
        }

        /// <summary>
        /// 将任务是否结束的决策权交给Scheduler
        /// </summary>
        /// <returns></returns>
        public virtual bool IsFetchFinished()
        {
            var requestCount = RemainingRequestCount();
            var fetcherCount = WorkingFetcherCount();
            if (fetcherCount > 0 || requestCount > 0)
            {
                return false;
            }

            if (_finished) return true;

            _finished = true;
            FinishNotify?.Invoke();

            return true;

        }


        #region IScheduler
        // 取链接和提交链接不需要特别关注亲缘性，因为需要强调亲缘性的都被AskForRequestsAssignment处理了
        public abstract Request Poll();
        protected abstract void PushWhenNoDuplicate(Request request);

        /// <summary>
        /// 在Ack中统计总的成功与失败计数
        /// </summary>
        /// <param name="request"></param>
        /// <param name="success">爬取成功或失败</param>
        public abstract void Ack(Request request, bool success);
        public abstract bool IsFirstRun();
        public abstract int WorkingFetcherCount();
        public abstract int RemainingRequestCount();
        public abstract FetchTaskProgress GetFetchProgress();
        public abstract void FetcherStatusReport(AbstractFetcher fetcher);
        #endregion

        #region IDuplicateRemover
        public abstract bool IsDuplicate(Request request);
        public abstract void ResetDuplicateCheck();
        public abstract void Dispose();
        #endregion
    }
}